/******************************************************************************

    Copyright (C) 2018 ErisedMedia
    All Rights Reserved.

    This source code and any compilation or derivative thereof is the
    proprietary information of ErisedMedia and is
    confidential in nature.
    Under no circumstances is this software to be exposed to or placed under an
    Open Source License of any type without the expressed written permission of
    ErisedMedia.

******************************************************************************/

/******************************************************************************

    File:   Tools.h
    Brief:  Tools的头文件，工具接口.

******************************************************************************/

/******************************************************************************

    Rev     Date        Author      Comments
--------------------------------------------------------------------------------
    001     20181120    RunyuanYe        Original

--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.

*******************************************************************************/
#ifndef _TOOLS_H_
#define _TOOLS_H_

/******************************************************************************
*
*   INCLUDE FILES
*
******************************************************************************/


/******************************************************************************
*
*   MACROS
*
******************************************************************************/

#define ENABLE_TIME_BENCHMARK_TEST  0

#define ENABLE_PROFILE_TIME_LOCK    1

#if ENABLE_TIME_BENCHMARK_TEST
#define START_PROFILE_TIME(name, info) \
    static ProfileTime name(info); name.StartTime()

#define END_PROFILE_TIME(name) \
    name.EndTime()

#define INTERVAL_PROFILE_TIME(name, info) \
    static ProfileTime name(info); name.FpsIntervalTime()

#define START_PROFILE_TIME_EX(name, info, frame) \
    static ProfileTime name(info, frame); name.StartTime()

#define INTERVAL_PROFILE_TIME_EX(name, info, time) \
    static ProfileTime name(info); name.FpsIntervalTime(time)

#else

#define START_PROFILE_TIME(name, info)

#define END_PROFILE_TIME(name)

#define INTERVAL_PROFILE_TIME(name, info)

#define START_PROFILE_TIME_EX(name, info, frame)

#define INTERVAL_PROFILE_TIME_EX(name, info, time)

#endif

#define THREAD_SCHED_OTHER  0
/*
    它是默认的线程分时调度策略，所有的线程的优先级别都是0，线程的调度是通过分时来完成的。简单地说，如果系统使用这种调度策略，程序将无法设置线程的优先级。请注意，
    这种调度策略也是抢占式的，当高优先级的线程准备运行的时候，当前线程将被抢占并进入等待队列。这种调度策略仅仅决定线程在可运行线程队列中的具有相同优先级的线程的运行次序。
*/
#define THREAD_SCHED_FIFO   1
/*
    它是一种实时的先进先出调用策略，且只能在超级用户下运行。这种调用策略仅仅被使用于优先级大于0的线程。它意味着，使用SCHED_FIFO的可运行线程将一直抢占使用SCHED_OTHER的运行线程J。
    此外SCHED_FIFO是一个非分时的简单调度策略，当一个线程变成可运行状态，它将被追加到对应优先级队列的尾部((POSIX 1003.1)。当所有高优先级的线程终止或者阻塞时，它将被运行。
    对于相同优先级别的线程，按照简单的先进先运行的规则运行。我们考虑一种很坏的情况，如果有若干相同优先级的线程等待执行，然而最早执行的线程无终止或者阻塞动作，那么其他线程是无法执行的，
    除非当前线程调用如pthread_yield之类的函数，所以在使用SCHED_FIFO的时候要小心处理相同级别线程的动作。
*/
#define THREAD_SCHED_RR     2
/*
    鉴于SCHED_FIFO调度策略的一些缺点，SCHED_RR对SCHED_FIFO做出了一些增强功能。从实质上看，它还是SCHED_FIFO调用策略。它使用最大运行时间来限制当前进程的运行，
    当运行时间大于等于最大运行时间的时候，当前线程将被切换并放置于相同优先级队列的最后。这样做的好处是其他具有相同级别的线程能在“自私“线程下执行。
*/

/******************************************************************************
*
*   TYPEDEFS
*
******************************************************************************/


/******************************************************************************
*
*   EXPORT DATA
*
******************************************************************************/


/******************************************************************************
*
*   EXPORT FUNCTION PROTOTYPES
*
******************************************************************************/

/*
    获取时钟Ticks，单位：毫秒

    返回时钟计数
*/
long long GetClockTicks();

/*
    获取时钟Ticks，单位：微秒

    返回时钟计数
*/
long long GetClockTicksEx();

/*
    获取文件大小

    file：为输入的文件

    成功返回文件大小，失败返回负值
*/
int GetFileSize(FILE* file);

/*
    获取文件大小

    fileName：为输入的文件名

    成功返回文件大小，失败返回负值
*/
int GetFileSizeEx(const char* fileName);

/*
    创建目录

    directory：要创建的目录名

    成功返回0，失败返回非0
*/
int MakeDirectory(const char* directory);

/*
    创建目录

    directory：要创建的目录名

    成功返回0，失败返回非0
*/
int MakeDirectorys(const char* directory);

/*
    创建目录

    directory：要创建的目录名

    成功返回0，失败返回非0
*/
int MakeDirectorysEx(const std::string& directory);

/*
    判断输入的路径是目录还是文件
    
    pPath : 目录或文件的路径

    返回0表示为目录，返回1表示为文件，返回-1表示失败，可能路径的文件或目录不存在
*/
int IsDirectory(const char *pPath);

/*
    删除文件或目录

    fileName：要删除的文件或目录名

    成功返回0，失败返回非0
*/
int DeleteFile(const char* fileName);

/*
    判断文件或目录是否存在

    fileName：要判断的文件或目录名

    存在返回true，不存在返回false
*/
bool HasFile(const char* fileName);

/*
    拷贝文件或目录

    dstFileName：目标文件或目录名
    srcFileName：源文件或目录名

    成功返回0，失败返回非0
*/
int CopyFile(const char* dstFileName, const char* srcFileName);

/*
    获取剩余内存，单位：KB

    成功返回剩余内存数量，失败返回-1
*/
int GetFreeMemSize();

/*
    执行命令

    cmdStr：要执行的命令字符串

    成功返回0，失败返回-1
*/
int RunCmd(const char* cmdStr);

#ifdef USE_UUID
/*
    生成UUID

    uuid：输出UUID字符串
*/
void GenerateUUID(char *puuid);

/*
    生成UUID

    uuid：输出UUID字符串
*/
void GenerateUUIDEx(std::string& uuid);
#endif

/*
    获取文件名

    fullFileName： 带目录的完整路径名
    needExt： 是否需要返回文件名的扩展名

    返回获取的文件名
*/
std::string GetFileName(std::string fullFileName, bool needExt=true);

/**
 * @brief Gets filename without extension
 * @param filepath - full file name
 * @return filename without extension
 */
std::string FileNameNoExt(const std::string &filepath);

/*
    把一个long long类型的变量赋值给另一个long long类型的变量

    避免地址不对齐时导致程序崩溃
*/
void LongLongAssign(void* dst, const void* src);

/*
    连接两个路径

    joinpath： 为输出的连接后的路径
    path1： 要连接的第1个路径
    path2： 要连接的第2个路径
*/
void JoinPath(std::string& joinpath, const std::string& path1, const std::string& path2);

/*
    连接两个路径

    path1： 要连接的第1个路径
    path2： 要连接的第2个路径

    返回连接后的路径
*/
std::string JoinPathEx(const std::string& path1, const std::string& path2);

std::vector<std::string> StringSplit(std::string& str, char splitChr);

/*
    th: c++的线程对象
    priority: 线程优先级，这里越小优先级越高，与pthread的相反，最高优先级为0
    policy: 线程调度策略，可为THREAD_SCHED_OTHER，THREAD_SCHED_FIFO，THREAD_SCHED_RR，默认使用THREAD_SCHED_RR

    成功返回0，失败返回-1
*/
int SetThreadSched(std::thread* th, int priority, int policy=THREAD_SCHED_RR);

class ProfileTime
{
public:
    ProfileTime(const char* infoString, int printFrameCount = 50, bool needPrint=true);
    ~ProfileTime();

    void StartTime();

    void EndTime();

    // time: ms
    void FpsIntervalTime(int time = 10000);

    float GetFps() const;
    float GetFrameTime() const;

protected:
    std::string m_infoString;
    long long m_totalTime;
    long long m_frameCount;
    long long m_startTime;
    long long m_endTime;
    int m_printFrameCount;

    long long m_intervalFrameCount;
    long long m_intervalStartTime;
    long long m_intervalEndTime;
    bool m_intervalIsFirst;

    bool m_needPrint;
    float m_fps;
    float m_time;

    #if ENABLE_PROFILE_TIME_LOCK
    std::mutex   m_lock;
    #endif
};

#endif //#ifndef _TOOLS_H_
